import numpy as np
import pandas as pd

# 读取数据
train = pd.read_csv('train.csv', index_col=False, header=None)
test = pd.read_csv('test.csv', index_col=False, header=None)

X = train.iloc[0:2].values.T
Y = train.iloc[2].values.T

# 数据z-score标准化
X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)

# sigmoid函数以及它的导数
def sigmoid_function(x):
    sigmoid = 1 / (1 + np.exp(-x))
    return sigmoid

def dc(x):
    x = sigmoid_function(x)
    dcs = x * (1 - x)
    return dcs




# 参数情况
input_size = 2
hidden_size = 8
output_size = 1

# 初始随机化（W,b）
W1 = np.random.uniform(low=-1/(3**(1/2)), high=1/(3**(1/2)), size=(input_size, hidden_size))
b1 = np.random.uniform(low=-1/(3**(1/2)), high=1/(3**(1/2)), size=(1, hidden_size))
W2 = np.random.uniform(low=-1/(3**(1/2)), high=1/(3**(1/2)), size=(hidden_size, output_size))
b2 = np.random.uniform(low=-1/(3**(1/2)), high=1/(3**(1/2)), size=(1, output_size))

# 前向传播:算出所有的（z,a,y)
def forward(X, W1, b1, W2, b2):
    Z1 = np.dot(X, W1) + b1
    A1 = sigmoid_function(Z1)
    Z2 = np.dot(A1, W2) + b2
    A2 = sigmoid_function(Z2)
    return Z1, Z2, A1, A2

# 后向传播：用链式法则求偏导并更新参数
def back(X, Y, W1, b1, W2, b2):
    alpha = 0.1 # 调整学习率以便收敛
    Z1, Z2, A1, A2 = forward(X, W1, b1, W2, b2)


    # 计算交叉熵函数的导数
    l = X.shape[0]
    D2 = (A2 - Y.reshape(-1, 1)) / l

    # 计算第二层的导数
    dw2 = np.dot(A1.T, D2)
    db2 = np.sum(D2, axis=0, keepdims=True)

    # 计算第一层的导数
    d1 = np.dot(D2, W2.T) * dc(Z1)
    dw1 = np.dot(X.T, d1)
    db1 = np.sum(d1, axis=0, keepdims=True)

    # 更新参数
    W1 = W1 - alpha * dw1
    b1 = b1 - alpha * db1
    W2 = W2 - alpha * dw2
    b2 = b2 - alpha * db2

    return W1, b1, W2, b2

# 训练模型
for i in range(10000):
    W1, b1, W2, b2 = back(X, Y, W1, b1, W2, b2)

# 在测试集上进行预测，并计算准确率
X_test = test.iloc[0:2].values.T
Y_test = test.iloc[2].values.T
Y_test = Y_test.astype(int)
X_test = (X_test - np.mean(X_test, axis=0)) / np.std(X_test, axis=0)
_, _, _, A2_test = forward(X_test, W1, b1, W2, b2)
preds = []
for i in range(len(A2_test)):
    if A2_test[i] > 0.5:
        preds.append(1)
    else:
        preds.append(0)

accuracy = np.sum(np.equal(preds ,Y_test))/len(Y_test)
print('Test accuracy:', accuracy)


